package cn.zhoutao.basic.service.impl;

import cn.zhoutao.basic.constants.BaseConstant;
import cn.zhoutao.basic.dto.RegisterDto;
import cn.zhoutao.basic.exception.BusinessException;
import cn.zhoutao.basic.service.IVerifyCodeService;
import cn.zhoutao.basic.util.SmsUtil;
import cn.zhoutao.basic.util.StrUtils;
import cn.zhoutao.basic.util.VerifyCodeUtils;
import cn.zhoutao.user.domain.User;
import cn.zhoutao.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;


/**
 * @Author:MrZhou
 * @Date:2022/6/15 21:55
 */
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;

    /**
     * 发送图形验证码
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        if(!StringUtils.hasLength(key)){
            throw new BusinessException("key不能为空！");
        }
        //每次都生成新的code，但是要覆盖前面的
        //生成code
        String code = StrUtils.getComplexRandomString(4);
        //保存到redis，设置过期时间  key相当于前端传给我的UUID，永远不会重复
        redisTemplate.opsForValue().set(key,//前端传的UUID
                code,//图片中生成的码
                5,//过期时间
                TimeUnit.MINUTES//过期时间的单位
        );
        //使用2d引擎把code画成图，把图用base64编码成字符串，返回base64编码的字符串
        return VerifyCodeUtils.VerifyCode(100,38,code);

    }

    /**
     * 发送短信验证码
     * @param dto
     */
    @Override
    public void smsCode(RegisterDto dto) {
        String phone = dto.getPhone();
        String imageCodeValue = dto.getImageCodeValue();
        String imageCodeKey = dto.getImageCodeKey();
//一：校验
//1.空校验
        if(StringUtils.isEmpty(phone) ||
                StringUtils.isEmpty(imageCodeValue) ||
                StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("信息填写异常！");
        }
//2.校验图形验证码，根据imageCodeKey从redis获取图形验证码
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
//。获取不到 图形验证码过期，重新获取
        if (imageCodeTmp==null){
            throw new BusinessException("图形验证码已过期，请重新获取！");
        }
//。获取到了，比对图形验证码是否正确 equalsIgnoreCase：比对是不区分大小写
        if (!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){
//        - 不正确，提示输入图形验证码错误
            throw new BusinessException("请输入正确的验证码！");
        }
//        - 正确，往下走
//3.校验手机号是否注册过了
        User userTmp = userMapper.loadByPhone(phone);
//。注册过了，滚去登录
        if (userTmp !=null){
            throw  new BusinessException("该电话已经注册过了，可以直接登陆！");
        }
//。没有注册过，往下走
//二：短信验证码逻辑
//1.根据手机号拼接key，159:register，从redis获取曾今可能发送的短信验证码
        String key = BaseConstant.RegisterConstants.REGISTER_SMS_PREFIX + phone;
        Object smsCodeTmp = redisTemplate.opsForValue().get(key);

//1.1 获取到了
        String smsCode = "";
        if (smsCodeTmp!=null){
//1.1.1 校验是否过了一分钟重发时间 value  9527:232468742341657213
            Long oldTime = Long.valueOf(smsCodeTmp.toString().split(":")[1]);
            if (System.currentTimeMillis()-oldTime <=1*60*1000){
//。小于一分钟  哥屋恩
                    throw new BusinessException("别慌，等哈再来！");
            }
//。大于一分中 （还没有到3分钟，验证码还有效），
//使用还没过期的验证码，刷新过期时间
            smsCode = smsCodeTmp.toString().split(":")[0];

        }else{
//1.2 获取不到
//1.2.1.生成新的短信验证码
            smsCode = StrUtils.getComplexRandomString(4);
        }
//3.存储redis 设置一个过期时间
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(
                key,
                smsCodeValue,
                3,
                TimeUnit.MINUTES
        );
//4.发送短信
        SmsUtil.sendSms(phone,"您的验证码是："+smsCode+"。请在3分钟之内使用！");
        System.out.println("您的验证码是：" + smsCode + "。请在3分钟之内使用！");
    }
}
